package com.house.framework.controller;

import com.alibaba.fastjson.JSONArray;
import com.house.annotations.FirsthandResponse;
import com.house.annotations.NoAuthentication;
import com.house.annotations.RequestDecrypt;
import com.house.annotations.ResponseEncrypt;
import com.house.common.IdBuilder;
import com.house.enhance.WeChatVo;
import com.house.utils.StringUtils;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@RequestMapping("/file")
public class FileController extends BaseController {

    @Autowired
    private Environment env;

    @ApiOperation(value = "文件上传", notes = "支持多文件上传，参数multipartFile")
    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    @NoAuthentication
    @RequestDecrypt(value = false)
    @ResponseEncrypt(value = false)
    public List<Map> upload(@RequestParam("multipartFile") MultipartFile multipartFile, @RequestParam("moduleName") String moduleName) throws IOException {
        List<MultipartFile> files = this.multipartFiles();
        String rootlPath = env.getProperty("filemappingpath");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        SimpleDateFormat ddf = new SimpleDateFormat("dd");
        List<Map> result = new ArrayList<>();
        for (MultipartFile file : files) {
            Map map = new HashMap();
            String fileAllName = file.getOriginalFilename();
            String extensionName = fileAllName.substring(fileAllName.lastIndexOf(".") + 1);
            String fileName = fileAllName.substring(0, fileAllName.lastIndexOf("."));
            String newFileName = IdBuilder.getUUID() + "." + extensionName;
            String filePath = "UploadFiles/" + moduleName + "/" + sdf.format(new Date()) + "/" + ddf.format(new Date()) + "/" + newFileName;
            String uploadPath = rootlPath + "/" + filePath;
            File saveFile = new File(uploadPath);
            File parentFile = saveFile.getParentFile();
            if (!parentFile.exists())
                parentFile.mkdirs();
            try (OutputStream out = new FileOutputStream(saveFile)) {
                out.write(file.getBytes());
            }
            map.put("FileAllName", fileAllName);
            map.put("FileUrl", filePath);
            map.put("NewFileName", newFileName);
            map.put("ExtensionName", extensionName);
            map.put("FileName", fileName);
            result.add(map);
        }
        return result;
    }

    @ApiOperation(value = "文件上传", notes = "支持多文件上传，参数multipartFile")
    @RequestMapping(value = "/uploadbyte", method = RequestMethod.POST)
    @NoAuthentication
    @RequestDecrypt(value = false)
    @ResponseEncrypt(value = false)
    public List<Map> uploadbyte(@RequestParam("multipartFile") MultipartFile multipartFile, @RequestParam("moduleName") String moduleName) throws IOException {
        List<MultipartFile> files = this.multipartFiles();
        String rootlPath = env.getProperty("filemappingpath");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        SimpleDateFormat ddf = new SimpleDateFormat("dd");
        List<Map> result = new ArrayList<>();
        for (MultipartFile file : files) {
            Map map = new HashMap();
            String fileAllName = file.getOriginalFilename() + ".png";
            String extensionName = fileAllName.substring(fileAllName.lastIndexOf(".") + 1);
            String fileName = fileAllName.substring(0, fileAllName.lastIndexOf("."));
            String newFileName = IdBuilder.getUUID() + "." + extensionName;
            String filePath = "UploadFiles/" + moduleName + "/" + sdf.format(new Date()) + "/" + ddf.format(new Date()) + "/" + newFileName;
            String uploadPath = rootlPath + "/" + filePath;
            File saveFile = new File(uploadPath);
            File parentFile = saveFile.getParentFile();
            if (!parentFile.exists())
                parentFile.mkdirs();
            try (OutputStream out = new FileOutputStream(saveFile)) {
                out.write(file.getBytes());
            }
            map.put("FileAllName", fileAllName);
            map.put("FileUrl", filePath);
            map.put("NewFileName", newFileName);
            map.put("ExtensionName", extensionName);
            map.put("FileName", fileName);
            result.add(map);
        }
        return result;
    }

    @ApiOperation(value = "文件上传", notes = "支持多文件上传，参数multipartFile")
    @RequestMapping(value = "/uploadbase64", method = RequestMethod.POST)
    @NoAuthentication
    @RequestDecrypt(value = false)
    @ResponseEncrypt(value = false)
    public List<Map> uploadbyte(HttpServletRequest request, HttpServletResponse response,
                                @RequestParam("base64Code") String imgData,
                                @RequestParam("moduleName") String moduleName) throws IOException {
        String rootlPath = env.getProperty("filemappingpath");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        SimpleDateFormat ddf = new SimpleDateFormat("dd");
        List<Map> result = new ArrayList<>();
        if (!"".equals(imgData)) {
            Map map = new HashMap();


            String fileAllName = sdf.format(new Date()) + ".png";
            String extensionName = fileAllName.substring(fileAllName.lastIndexOf(".") + 1);
            String fileName = fileAllName.substring(0, fileAllName.lastIndexOf("."));
            String newFileName = IdBuilder.getUUID() + "." + extensionName;
            String filePath = "UploadFiles/" + moduleName + "/" + sdf.format(new Date()) + "/" + ddf.format(new Date()) + "/" + newFileName;
            String uploadPath = rootlPath + "/" + filePath;
            File saveFile = new File(uploadPath);
            File parentFile = saveFile.getParentFile();
            if (!parentFile.exists()) parentFile.mkdirs();

            try (OutputStream out = new FileOutputStream(saveFile)) {
                byte[] b = Base64.decodeBase64(imgData);
                for (int i = 0; i < b.length; ++i) {
                    if (b[i] < 0) {// 调整异常数据
                        b[i] += 256;
                    }
                }
                out.write(b);
            }
            map.put("FileAllName", fileAllName);
            map.put("FileUrl", filePath);
            map.put("NewFileName", newFileName);
            map.put("ExtensionName", extensionName);
            map.put("FileName", fileName);
            result.add(map);
        }
        return result;

    }

    /**
     * @Description: 微信 上传
     * @Author: ArvinWoo
     * @Date: 2022/12/27 18:24
     * @MethodName: uploadWX
     * @Param: [type, request]
     * @Return: com.jokeep.enhance.WeChatVo
     **/
    @SneakyThrows
    @PostMapping("/uploadWX")
    @NoAuthentication
    @RequestDecrypt(value = false)
    @ResponseEncrypt(value = false)
    @FirsthandResponse
    public WeChatVo uploadWX(String type, HttpServletRequest request) {
        MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
        MultipartFile file = req.getFile("file");
        String moduleName = req.getParameter("moduleName");
        moduleName = (null != moduleName && StringUtils.isNotEmpty(moduleName)) ? moduleName : "";
        String rootlPath = env.getProperty("filemappingpath");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Map<String, Object> result = new LinkedHashMap<>();
        String fileAllName = file.getOriginalFilename();
        long fileSize = file.getSize();
        String extensionName = fileAllName.substring(fileAllName.lastIndexOf(".") + 1);
        String fileName = fileAllName.substring(0, fileAllName.lastIndexOf("."));
        String newFileName = IdBuilder.getUUID() + "." + extensionName;
        String filePath = "/UploadFiles/" + moduleName + "/" + sdf.format(new Date()) + "/" + newFileName;
        String uploadPath = rootlPath + filePath;
        File saveFile = new File(uploadPath);
        File parentFile = saveFile.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        try (OutputStream out = new FileOutputStream(saveFile)) {
            out.write(file.getBytes());
        }
        result.put("FileAllName", fileAllName);
        result.put("FileUrl", filePath);
        result.put("NewFileName", newFileName);
        result.put("ExtensionName", extensionName);
        result.put("FileName", fileName);
        //---需要字段
        result.put("F_FileType", extensionName);
        result.put("F_StorageFile", newFileName);
        result.put("F_FileName", newFileName);
        result.put("SaveFilePath", filePath);
        result.put("F_FileSize", fileSize);
        JSONArray array = new JSONArray();
        array.add(result);
        return WeChatVo.fileSuccess(array);

    }

    /**
     * @Description: uniapp 上传
     * @Author: ArvinWoo
     * @Date: 2022/12/27 18:24
     * @MethodName: uploadWX
     * @Param: [type, request]
     * @Return: JSONArray
    **/
    @SneakyThrows
    @PostMapping("/uploadUniApp")
    @NoAuthentication
    @RequestDecrypt(value = false)
    @ResponseEncrypt(value = false)
    @FirsthandResponse
    public JSONArray uploadUniApp(String type, HttpServletRequest request) {
        MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
        MultipartFile file = req.getFile("file");
        String fileAllName = "";
        if(null == file){
            Map<String, MultipartFile> fileMap = req.getFileMap();
            for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
                file = entry.getValue();
                fileAllName = entry.getKey();
            }
        }
        String moduleName = req.getParameter("moduleName");
        moduleName = (moduleName == null) ? req.getParameter("moduleName") : moduleName;
        moduleName = (null != moduleName && StringUtils.isNotEmpty(moduleName)) ? moduleName : "";
        String rootlPath = env.getProperty("filemappingpath");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Map<String, Object> result = new LinkedHashMap<>();
        long fileSize = file.getSize();
        String extensionName = fileAllName.substring(fileAllName.lastIndexOf(".") + 1);
        String fileName = fileAllName.substring(0, fileAllName.lastIndexOf("."));
        String newFileName = IdBuilder.getUUID() + "." + extensionName;
        String filePath = "/UploadFiles/" + moduleName + "/" + sdf.format(new Date()) + "/" + newFileName;
        String uploadPath = rootlPath + filePath;
        File saveFile = new File(uploadPath);
        File parentFile = saveFile.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        try (OutputStream out = new FileOutputStream(saveFile)) {
            out.write(file.getBytes());
        }
        result.put("F_STORAGEPATH", fileAllName);
        result.put("F_THUMSTORAGEPATH", fileAllName);
        result.put("FILEURL", filePath);
        result.put("NEWFILENAME", newFileName);
        result.put("EXTENSIONNAME", extensionName);
        result.put("FILENAME", fileName);
        //---需要字段
        result.put("FILEURL", filePath);
        result.put("F_FILETYPE", extensionName);
        result.put("F_STORAGEFILE", newFileName);
        result.put("F_FILENAME", newFileName);
        result.put("SAVEFILEPATH", filePath);
        result.put("F_FILESIZE", fileSize);
        JSONArray array = new JSONArray();
        array.add(result);
        return array;
    }


    @ApiOperation(value = "文件下载", notes = "sourcePath文件相对地址；targetName下载文件名")
    @RequestMapping(value = "/download", method = RequestMethod.GET)
    @NoAuthentication
    @RequestDecrypt(value = false)
    @ResponseEncrypt(value = false)
    public void downloadWarFile(HttpServletRequest request, HttpServletResponse response, @RequestParam String sourcePath, @RequestParam String targetName) throws IOException {
        String filePath = env.getProperty("filemappingpath");
        String fileType = sourcePath.substring(sourcePath.lastIndexOf("."));
        File file = new File(filePath + "/" + sourcePath);
        String mimeType = request.getServletContext().getMimeType(targetName);
        response.setContentType(mimeType);
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(targetName, "UTF-8"));
        response.setCharacterEncoding("UTF-8");
        byte[] buff = new byte[1024];
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); OutputStream os = response.getOutputStream()) {
            int i = bis.read(buff);
            while (i != -1) {
                os.write(buff, 0, buff.length);
                os.flush();
                i = bis.read(buff);
            }
        }
    }

    private static int byteIndexOf(byte[] b, String s, int start) {
        return byteIndexOf(b, s.getBytes(), start);
    }

    private static int byteIndexOf(byte[] b, byte[] s, int start) {
        int i;
        if (s.length == 0) {
            return 0;
        }
        int max = b.length - s.length;
        if (max < 0) {
            return -1;
        }
        if (start > max) {
            return -1;
        }
        if (start < 0) {
            start = 0;
        }
        // 在b中找到s的第一个元素
        search: for (i = start; i <= max; i++) {
            if (b[i] == s[0]) {
                // 找到了s中的第一个元素后，比较剩余的部分是否相等
                int k = 1;
                while (k < s.length) {
                    if (b[k + i] != s[k]) {
                        continue search;
                    }
                    k++;
                }
                return i;
            }
        }
        return -1;
    }

    private static byte[] subBytes(byte[] b, int from, int end) {
        byte[] result = new byte[end - from];
        System.arraycopy(b, from, result, 0, end - from);
        return result;
    }

    private static String subBytesString(byte[] b, int from, int end) {
        return new String(subBytes(b, from, end));
    }
}
